<?php
namespace app\api\behavior;

use jwt\Jwt;
use think\Controller;
use think\facade\Cache;
use think\facade\Request;
use think\facade\Config;

class Auth extends Controller {
    
    /**
     * @desc 随机字符串
     * @example 27846a2f-28c6-4fa4-82fd-6f0d3d3ea2ce
     * @var
     */
    protected $_nonce;
    
    /**
     * @desc 时间戳
     * @example 1559959745
     * @var
     */
    protected $_timestamp;
    
    
    public function __construct() {
        $this->_timestamp = Request::post('timestamp');
        $this->_nonce = Request::post('nonce');
    }
    
    /**
     * @desc 获取用户基础信息
     * @param Request $request
     * @return array|void|bool
     * @throws \HttpResponseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function run() {
        if(!$this->_timestamp || !$this->_nonce){
            $data = [
                'errorCode' => EC_MISSING_PARAMETERS,
                'message' => Config::pull('errorcode')[EC_MISSING_PARAMETERS]
            ];
            return response_exception($data);
        }
        
        //排除不执行校验Token的方法, 配置文件中配置
        $request    = Request::instance();
        $authAllow  = Config::get('common.api_auth_allow');
        $controller = strtolower($request->controller());
        $action     = $request->action(true);

        //获取所有post参数
        $postData = Request::post();

        //不验证Auth-Token的控制器
        if(in_array($controller, $authAllow['controller'])) {
            //验证getAccessToken的签名
            if (!checkSign($postData, $postData['secretKey'])) {
                $data = [
                    'errorCode' => EC_SIGN_ERROR,
                    'message'   => Config::pull('errorcode')[EC_SIGN_ERROR]
                ];
                return response_exception($data);
            }
            return;
        }
        
        //从header获取Token
        $token     = $request->header('Auth-Token');
        
        //验证token合法性
        $tokenError = [
            'errorCode' => EC_ACCESS_TOKEN_ERROR,
            'message'   => Config::pull('errorcode')[EC_ACCESS_TOKEN_ERROR]
        ];
        try{
            $tokenInfo = Jwt::decode($token, Config::get('token_sign_key'));
            if(false === $tokenInfo) {
                return response_exception($tokenError);
            }
        }catch (\Exception $e) {
            return response_exception($tokenError);
        }

        if(false === $tokenInfo) {
            $data = [
                'errorCode' => EC_ACCESS_TOKEN_ERROR,
                'message'   => Config::pull('errorcode')[EC_ACCESS_TOKEN_ERROR]
            ];
            return response_exception($data);
        }
        
        //redis里存每个userId对应token的创建时间，如果redis里的创建时间大于token里面的过期时间，则自动退出
        $tokenExpireTime = Cache::tag('member')->get(Config::get('token_cache_key') . $tokenInfo->userId . '_expire');
        
        if(empty($tokenExpireTime) || time() > $tokenExpireTime) {
            $data = [
                'errorCode' => EC_ACCESS_TOKEN_EXPIRED,
                'message'   => Config::pull('errorcode')[EC_ACCESS_TOKEN_EXPIRED]
            ];
            return response_exception($data);
        }
    
        //验证通过，记录USER_ID
        define('API_USER_ID', $tokenInfo->userId);
    
        //刷新过期时间
        //Cache::tag('member')->set(Config::get('token_cache_key') . $tokenInfo->userId .'_expire', time() + Config::get('token_expires'));

        //验证所有方法签名的正确性, secretKey从AccessToken里解析出来
        if (!checkSign($postData, $tokenInfo->secretKey)) {
            $data = [
                'errorCode' => EC_SIGN_ERROR,
                'message'   => Config::pull('errorcode')[EC_SIGN_ERROR]
            ];
            return response_exception($data);
        }
    }
}